package net.alche.fa.core.doing;

import java.lang.Override;
import net.alche.fa.core.model.Logic;
import net.alche.fa.core.model.FaValue;
import net.alche.fa.core.CodeLevel;
import net.alche.fa.core.SageStone;
import net.alche.fa.core.FaException;
import java.util.Date;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.lang.reflect.Array;
import net.alche.fa.core.FaClassConf;
import net.alche.fa.core.FaClass;

// 创建对象
@FaAnnoDoing
@SuppressWarnings("all")
public class NewDo extends AbstractDoing {

  @Override
  public boolean matched(String what, Logic g) {
    return "new".equals(what);
  }

  @Override
  public FaValue doing(Logic g, CodeLevel lvl, SageStone st) throws FaException {
    String className = g.getObj();
    FaValue fav = null;
    if ("Date".equals(className)) {
      fav = new FaValue(new Date(), FaValue._DATE);
    } else if (className.startsWith("HashMap") || className.startsWith("LinkedHashMap")) {
      fav = this.newMap(className);
    } else if (className.startsWith("ArrayList") || className.startsWith("LinkedList")) {
      fav = this.newList(className);
    } else if (className.endsWith("[]")) {
      fav = this.newArray(className, st, lvl, g);
    } else if (super.plat.isSageName(className)) {
      fav = this.newSageStone(className, st, lvl, g);
    } else if ((className.startsWith("$$"))) {
      fav = this.newSageStoneInner(className, st, lvl, g);
    } else {
      fav = this.newObj(className, st, lvl, g);
    }
    fav.setObjType(className);
    return fav;
  }

  // new Map
  public FaValue newMap(String className) {
    Map<String, FaValue> map = null;
    if (className.startsWith("LinkedHashMap")) {
      map = new LinkedHashMap<>();
    } else {
      map = new HashMap<>();
    }
    FaValue fav = new FaValue(map, FaValue._MAP);
    return fav;
  }

  // List
  public FaValue newList(String className) {
    FaValue fav = null;
    if (className.startsWith("LinkedList")) {
      fav = new FaValue(new LinkedList<FaValue>(), FaValue._LIST);
    } else {
      fav = new FaValue(new ArrayList<FaValue>(), FaValue._LIST);
    }
    return fav;
  }

  // Array
  public FaValue newArray(String className, SageStone st, CodeLevel lvl, Logic g) throws FaException {
    FaValue fav = new FaValue();
    fav.setNull(false);
    fav.setType(FaValue._ARR);
    List<FaValue> favList = getFaValueList(st, lvl, g);
    if (favList == null || favList.isEmpty()) {
      throw new FaException(FaException.LESS_PARAM, "new array min 1 param!");
    }
    className = className.substring(0, className.length() - 2);
    Class cls;
    if (this.plat.isSageName(className)) {
      cls = FaValue.class;
    } else {
      cls = this.plat.getFaDo().getObjClass(className);
    }
    Object arrObj;
    // 指定长度
    if (favList.size() == 1 && favList.get(0).getType() == FaValue._INT) {
      int arrLength = favList.get(0).getIntValue();
      arrObj = Array.newInstance(cls, arrLength);
    } else { // 指定参数
      arrObj = Array.newInstance(cls, favList.size());
      int i = 0;
      for (FaValue item : favList) {
        Array.set(arrObj, i, item.getValue());
        i++;
      }
    }
    fav.setObjValue(arrObj);
    return fav;
  }

  // sage stone
  public FaValue newSageStoneInner(String className, SageStone st, CodeLevel lvl, Logic g) throws FaException {
    FaClassConf faClassConf = st.getFaClass().getConf().getInner().get(className);
    FaClass fac = faClassConf.instance(lvl);
    if (st.getVars() != null) {
      for (FaValue fv : st.getVars().values()) {
        fac.getThisSage().putVar(fv.getVarName(), fv);
      }
    }
    if (st.get_this() != null) {
      fac.getThisSage().setOuter(st.get_this());
    }
    FaValue fav = new FaValue(fac.getThisSage(), FaValue._SAGE);
    // List<FaValue> faList = super.getFaValueList(st, lvl, g)
    // if faList != null && !faList.isEmpty()
    // fav.getSageValue().getFaClass().call(className, faList, lvl)
    return fav;
  }

  // sage stone
  public FaValue newSageStone(String className, SageStone st, CodeLevel lvl, Logic g) throws FaException {
    FaClassConf faClassConf = super.plat.getClassMap().get(className);
    FaClass fac = faClassConf.instance(lvl);
    FaValue fav = new FaValue(fac.getThisSage(), FaValue._SAGE);
    List<FaValue> faList = super.getFaValueList(st, lvl, g);
    if (faList != null && !faList.isEmpty()) {
      fav.getSageValue().getFaClass().call(className, faList, lvl);
    }
    return fav;
  }

  // new 其他对象
  public FaValue newObj(String className, SageStone st, CodeLevel lvl, Logic g) throws FaException {
    FaValue fav = new FaValue();
    fav.setNull(false);
    fav.setType(FaValue._OBJECT);
    fav.setObjType(className);
    List<FaValue> favList = getFaValueList(st, lvl, g);
    Object obj = null; // NewIo.newStart(className, favList)
    if (obj == null) {
      obj = this.plat.getFaDo().newInstance(className, super.parseToJavaArr(favList));
    }
    fav.setObjValue(obj);
    return fav;
  }
}